use core::intrinsics::unlikely;

use bits::{BitsOps, IntoBits};

use crate::MissAlignedError;

pub struct AlignedAddr<T, const POWER: u32> {
    addr: T,
}
impl<T, const POWER: u32> AlignedAddr<T, POWER>
where
    T: IntoBits
        + core::ops::Shl<u32, Output = T>
        + core::ops::Add<Output = T>
        + From<u8>
        + core::ops::Shr<usize, Output = T>,
{
    pub fn new(addr: T) -> Result<Self, MissAlignedError> {
        if addr.bits(0..=POWER - 1).is_clr() {
            Ok(Self { addr })
        } else {
            Err(MissAlignedError())
        }
    }
    /// 如地址 0x123000 为 4KB 对齐，那么 0x123 即为 base。
    pub fn from_base(base: T) -> Self {
        Self {
            addr: base << POWER,
        }
    }
    /// 获取基地址，如地址 0x123000 为 4KB 对齐，那么 0x123 即为 base。
    pub fn base(&self) -> T {
        self.addr >> (POWER as usize)
    }
    pub fn raw(&self) -> T {
        self.addr
    }
    pub fn is_aligned(&self) -> bool {
        self.addr.bits(0..=POWER - 1).is_clr()
    }
    /// 向前适配对齐地址，如 0x12345678 向前 12KB 对齐：变成地址 0x12346000
    pub fn fit_forward(addr: T) -> Self {
        if unlikely(addr.bits(0..=POWER - 1).is_clr()) {
            Self { addr }
        } else {
            Self {
                addr: addr.bits(0..=POWER - 1).clr() + T::from(1u8) << POWER,
            }
        }
    }
    /// 向后适配对齐地址，如 0x12345678 向后 12KB 对齐：变成地址 0x12345000
    pub fn fit_backward(addr: T) -> Self {
        Self {
            addr: addr.bits(0..=POWER - 1).clr(),
        }
    }
}

impl<const POWER: u32> Into<u32> for AlignedAddr<u32, POWER> {
    fn into(self) -> u32 {
        self.raw()
    }
}
impl<const POWER: u32> Into<u64> for AlignedAddr<u64, POWER> {
    fn into(self) -> u64 {
        self.raw()
    }
}
